/*
 * maz_drv_gpio.c
 *
 *  Created on: Jun 7, 2020
 *      Author: Paul
 */

#include "maz_drv_gpio.h"

/**
 * "dlvl" variables must be defined if debug message is to be printed through the dlog/dmsg, and "dlvl" must be declared static
 */
static int dlvl = DINF;

/* Internal Interface Functions */
int MAZ_Drv_gpio_debugcmd_rigister(void);

int MAZ_Drv_gpio_init(void)
{
    int ret = 0;

#if (MENABLE == MAZDRV_GPIO_DCMD_ENABLE)
    ret = MAZ_Drv_gpio_debugcmd_rigister();
#endif /* MAZDRV_GPIO_DCMD_ENABLE */

    return ret;
}

int MAZ_Drv_gpio_clk_enable(GPIO_TypeDef *port)
{
    if(GPIOA == port)
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();
    }
    else if(GPIOB == port)
    {
        __HAL_RCC_GPIOB_CLK_ENABLE();
    }
    else if(GPIOC == port)
    {
        __HAL_RCC_GPIOC_CLK_ENABLE();
    }
    else if(GPIOH == port)
    {
        __HAL_RCC_GPIOH_CLK_ENABLE();
    }
    else
    {
        return MAZRET_NG;
    }

    return MAZRET_OK;
}

#if (MENABLE == MAZDRV_GPIO_DCMD_ENABLE)
int MAZ_DBGCMD_gpio_init(void *cmd, char *param)
{
    int flag = -1;                      // 参数不合法标志
    int num = 0;                        // 引脚编号
    int mode = 0;                       // 工作模式
    int pull = 0;                       // 上下拉使能
    char *str;                          // 暂存解析参数得到的目标字符串
    char *tmp;                          // 暂存解析参数剩余的字符串
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    GPIO_TypeDef *GPIOx;

    str = strtok_r(param, " ", &tmp);
    if (NULL != str)
    {
        num = atoi(str);
        str = strtok_r(NULL, " ", &tmp);
        if (NULL != str)
        {
            mode = atoi(str);
            str = strtok_r(NULL, " ", &tmp);
            if (NULL != str)
            {
                pull = atoi(str);
                flag = 0;
            }
        }
    }

    /* Sub command without parameter  */
    if (flag)
    {
        printf("usage: gpio init <pinnum> <mode> <pull>\r\n");
        printf("   eg: gpio init 45 1 0\r\n");
        printf("pinnum: port * 16 + pin\r\n");
        printf("   0: PA0\r\n");
        printf("   1: PA1\r\n");
        printf("   2: PA2\r\n");
        printf("   ...\r\n");
        printf("   16: PB0\r\n");
        printf("   17: PB1\r\n");
        printf("   ...\r\n");
        printf("   112: PH0\r\n");
        printf("   ...\r\n");
        printf("mode:\r\n");
        printf("   %d: INPUT\r\n", GPIO_MODE_INPUT);
        printf("   %d: OUTPUT_PP\r\n", GPIO_MODE_OUTPUT_PP);
        printf("   %d: OUTPUT_OD\r\n", GPIO_MODE_OUTPUT_OD);
        printf("pull:\r\n");
        printf("   %d: NOPULL\r\n", GPIO_NOPULL);
        printf("   %d: PULLUP\r\n", GPIO_PULLUP);
        printf("   %d: PULLDOWN\r\n", GPIO_PULLDOWN);
        return MAZRET_OK;
    }

    GPIOx = (GPIO_TypeDef *)(GPIOA_BASE + 0x400 * (num >> 4));
    dmsg(DBUG, "num/mode/pull = %d/%d/%d\r\n", num, mode, pull);

    /* 判断参数有效性 */
    // to do

    MAZ_Drv_gpio_clk_enable(GPIOx);

    GPIO_InitStruct.Pin = 1 << (num & 0xf);             // GPIO_PIN_0
    GPIO_InitStruct.Mode = mode;                        // GPIO_MODE_INPUT
    GPIO_InitStruct.Pull = pull;                        // GPIO_NOPULL
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);

    return MAZRET_OK;
}

int MAZ_DBGCMD_gpio_get(void *cmd, char *param)
{
    int flag = -1;                      // 参数不合法标志
    int num = 0;                        // 引脚编号
    int val = 0;                        // 引脚状态值
    char *str;                          // 暂存解析参数得到的目标字符串
    char *tmp;                          // 暂存解析参数剩余的字符串
    GPIO_TypeDef *GPIOx;

    str = strtok_r(param, " ", &tmp);
    if (NULL != str)
    {
        num = atoi(str);
        flag = 0;
    }

    /* Sub command without parameter  */
    if (flag)
    {
        printf("usage: gpio get <pinnum>\r\n");
        printf("   eg: gpio get 45\r\n");
        printf("pinnum: port * 16 + pin\r\n");
        printf("   0: PA0\r\n");
        printf("   1: PA1\r\n");
        printf("   2: PA2\r\n");
        printf("   ...\r\n");
        printf("   16: PB0\r\n");
        printf("   17: PB1\r\n");
        printf("   ...\r\n");
        printf("   112: PH0\r\n");
        printf("   ...\r\n");
        return MAZRET_OK;
    }

    dmsg(DBUG, "num = %d\r\n", num);

    /* 判断参数有效性 */
    // to do

    /* Sub command with parameter */
    GPIOx = (GPIO_TypeDef *)(GPIOA_BASE + 0x400 * (num >> 4));
    val = HAL_GPIO_ReadPin(GPIOx, 1 << (num & 0xf));

    printf("%d\r\n", val);

    return MAZRET_OK;
}

int MAZ_DBGCMD_gpio_set(void *cmd, char *param)
{
    int flag = -1;                      // 参数不合法标志
    int num = 0;                        // 引脚编号
    int val = 0;                        // 写入引脚的值
    char *str;                          // 暂存解析参数得到的目标字符串
    char *tmp;                          // 暂存解析参数剩余的字符串
    GPIO_TypeDef *GPIOx;

    str = strtok_r(param, " ", &tmp);
    if (NULL != str)
    {
        num = atoi(str);
        str = strtok_r(NULL, " ", &tmp);
        if (NULL != str)
        {
            val = atoi(str);
            flag = 0;
        }
    }

    /* Sub command without parameter  */
    if (flag)
    {
        printf("usage: gpio set <pinnum> <val>\r\n");
        printf("   eg: gpio set 45 1\r\n");
        printf("pinnum: port * 16 + pin\r\n");
        printf("   0: PA0\r\n");
        printf("   1: PA1\r\n");
        printf("   2: PA2\r\n");
        printf("   ...\r\n");
        printf("   16: PB0\r\n");
        printf("   17: PB1\r\n");
        printf("   ...\r\n");
        printf("   112: PH0\r\n");
        printf("   ...\r\n");
        printf("val:\r\n");
        printf("   1: HIGH\r\n");
        printf("   0: LOW\r\n");

        return MAZRET_OK;
    }

    /* Sub command with parameter */
    dmsg(DBUG, "num/val = %d/%d\r\n", num, val);

    /* 判断参数有效性 */
    // to do

    /* Sub command with parameter */
    GPIOx = (GPIO_TypeDef *)(GPIOA_BASE + 0x400 * (num >> 4));
    HAL_GPIO_WritePin(GPIOx, 1 << (num & 0xf), val);

    return MAZRET_OK;
}

int MAZ_DBGCMD_gpio_engine(void *cmd, char *param)
{
    int flag = -1;                      // 参数不合法标志
    char *str;                          // 暂存解析参数得到的目标字符串
    char *tmp;                          // 暂存解析参数剩余的字符串
    GPIO_TypeDef *GPIOx;
    int port = -1;
    char *name = NULL;

    str = strtok_r(param, " ", &tmp);
    if (NULL != str)
    {
        port = atoi(str);
        flag = 0;
    }

    if (flag)
    {
        printf("%-8s %-12s %-12s %-12s %-12s %-12s\r\n", "PORT", "MODER", "OTYPER", "OSPEEDR", "PUPDR", "IDR");
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOA", \
               GPIOA->MODER, GPIOA->OTYPER, GPIOA->OSPEEDR, GPIOA->PUPDR, GPIOA->IDR);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOB", \
               GPIOB->MODER, GPIOB->OTYPER, GPIOB->OSPEEDR, GPIOB->PUPDR, GPIOB->IDR);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOC", \
               GPIOC->MODER, GPIOC->OTYPER, GPIOC->OSPEEDR, GPIOC->PUPDR, GPIOC->IDR);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOH", \
               GPIOH->MODER, GPIOH->OTYPER, GPIOH->OSPEEDR, GPIOH->PUPDR, GPIOH->IDR);

        printf("%-8s %-12s %-12s %-12s %-12s %-12s\r\n", "PORT", "ODR", "BSRR", "LCKR", "AFR[0]", "AFR[1]");
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOA", \
               GPIOA->ODR, GPIOA->BSRR, GPIOA->LCKR, GPIOA->AFR[0], GPIOA->AFR[1]);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOB", \
               GPIOB->ODR, GPIOB->BSRR, GPIOB->LCKR, GPIOB->AFR[0], GPIOB->AFR[1]);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOC", \
               GPIOC->ODR, GPIOC->BSRR, GPIOC->LCKR, GPIOC->AFR[0], GPIOC->AFR[1]);
        printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", "GPIOH", \
               GPIOH->ODR, GPIOH->BSRR, GPIOH->LCKR, GPIOH->AFR[0], GPIOH->AFR[1]);

        return MAZRET_OK;
    }

    /* 判断参数有效性 */
    if (port < 0 || port >= 4)
    {
        printf("err: port %d out of range.\r\n", port);
        printf("usage: gpio engine <port>\r\n");
        printf("   0: GPIOA\r\n");
        printf("   1: GPIOB\r\n");
        printf("   2: GPIOC\r\n");
        printf("   3: GPIOH\r\n");
        return MAZRET_OK;
    }

    switch(port)
    {
        case 0:
            GPIOx = GPIOA;
            name = "GPIOA";
            break;
        case 1:
            GPIOx = GPIOB;
            name = "GPIOB";
            break;
        case 2:
            GPIOx = GPIOC;
            name = "GPIOC";
            break;
        case 3:
            GPIOx = GPIOH;
            name = "GPIOH";
            break;
    }

    printf("%-8s %-12s %-12s %-12s %-12s %-12s\r\n", "PORT", "MODER", "OTYPER", "OSPEEDR", "PUPDR", "IDR");
    printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", name, \
           GPIOx->MODER, GPIOx->OTYPER, GPIOx->OSPEEDR, GPIOx->PUPDR, GPIOx->IDR);
    printf("%-8s %-12s %-12s %-12s %-12s %-12s\r\n", "PORT", "ODR", "BSRR", "LCKR", "AFR[0]", "AFR[1]");
    printf("%-8s 0x%08lx   0x%08lx   0x%08lx   0x%08lx   0x%08lx\r\n", name,
           GPIOx->ODR, GPIOx->BSRR, GPIOx->LCKR, GPIOx->AFR[0], GPIOx->AFR[1]);

    return MAZRET_OK;
}

int MAZ_DBGCMD_gpio_dlvl(void *cmd, char *param)
{
    int flag = -1;                      // 参数不合法标志
    int level = -1;                     // 解析到的打印等级配置
    char *str;                          // 暂存解析参数得到的目标字符串
    char *tmp;                          // 暂存解析参数剩余的字符串

    str = strtok_r(param, " ", &tmp);
    if (NULL != str)
    {
        level = atoi(str);
        flag = 0;
    }

    /* Sub command without parameter  */
    if (flag)
    {
        printf("%s(%d)\r\n",
               (DERR == dlvl) ? "DERR" : \
               (DWAN == dlvl) ? "DWAN" : \
               (DINF == dlvl) ? "DINF" : \
               (DBUG == dlvl) ? "DBUG" : \
               "DIGN", dlvl);
        return MAZRET_OK;
    }

    /* Sub command with parameter */
    if (level < DERR || level > DIGN)
    {
        printf("err: level %d out of range\r\n", level);
        printf("level:\r\n");
        printf("   DERR 0   error\r\n");
        printf("   DWAN 1   warning\r\n");
        printf("   DINF 2   information\r\n");
        printf("   DBUG 3   debug\r\n");
        printf("   DIGN 4   ignore\r\n");
        return MAZRET_OK;
    }

    dlvl = level;
    printf("dlvl = %s(%d)\r\n",
           (DERR == dlvl) ? "DERR" : \
           (DWAN == dlvl) ? "DWAN" : \
           (DINF == dlvl) ? "DINF" : \
           (DBUG == dlvl) ? "DBUG" : \
           "DIGN", dlvl);

    return MAZRET_OK;
}

static MAZCPNT_MAIN_CMD mcmd_gpio           = { "gpio",     "gpio engine debug command." };
static MAZCPNT_SUB_CMD  scmd_gpio_init      = { "init",     "gpio init <pin> <mode> <pull>.",   MAZ_DBGCMD_gpio_init };
static MAZCPNT_SUB_CMD  scmd_gpio_get       = { "get",      "gpio get <pin>.",                  MAZ_DBGCMD_gpio_get };
static MAZCPNT_SUB_CMD  scmd_gpio_set       = { "set",      "gpio set <pin> <val>.",            MAZ_DBGCMD_gpio_set };
static MAZCPNT_SUB_CMD  scmd_gpio_engine    = { "engine",   "gpio engine.",                     MAZ_DBGCMD_gpio_engine };
static MAZCPNT_SUB_CMD  scmd_gpio_dlvl      = { "dlvl",     "gpio dlvl [level].",               MAZ_DBGCMD_gpio_dlvl };

int MAZ_Drv_gpio_debugcmd_rigister(void)
{
    MAZ_CPNT_debugcmd_mcmd_register(&mcmd_gpio);
    MAZ_CPNT_debugcmd_scmd_register(&mcmd_gpio, &scmd_gpio_init);
    MAZ_CPNT_debugcmd_scmd_register(&mcmd_gpio, &scmd_gpio_get);
    MAZ_CPNT_debugcmd_scmd_register(&mcmd_gpio, &scmd_gpio_set);
    MAZ_CPNT_debugcmd_scmd_register(&mcmd_gpio, &scmd_gpio_engine);
    MAZ_CPNT_debugcmd_scmd_register(&mcmd_gpio, &scmd_gpio_dlvl);

    return MAZRET_OK;
}

#endif /* MAZDRV_GPIO_DCMD_ENABLE */
